﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Crochet.Core.Policy
{
	public class RescheduleOnExceptionExecutionPolicy : BaseExecutionPolicy
	{
		protected bool	bForceThrow;
		protected int	iRetries, iDelay, iCurrentExecution;

		public RescheduleOnExceptionExecutionPolicy(int iRetries, int iDelay, bool bForceThrow)
			: this(null, null, null, iRetries, iDelay, bForceThrow)
		{
		}

		public RescheduleOnExceptionExecutionPolicy(IScheduler sRootScheduler, SchedulerDelegate sdSchedulerProcess, ExceptionHandlerDelegate ehdExceptionHandlerDelegate, int iRetries, int iDelay, bool bForceThrow)
			: base(sRootScheduler, sdSchedulerProcess, ehdExceptionHandlerDelegate)
		{
			iCurrentExecution	= 0;
			this.iDelay			= iDelay;
			this.iRetries		= iRetries;
			this.bForceThrow	= bForceThrow;
		}

		public override void Execute(IScheduler sSourceScheduler)
		{
			if (iCurrentExecution < iRetries)
			{
				try
				{
					sdSchedulerProcess(sSourceScheduler);
				}
				catch(Exception eException)
				{
					if (iCurrentExecution++ >= (iRetries - 1))
					{
						if (ehdExceptionHandlerDelegate != null)
						{
							ehdExceptionHandlerDelegate(eException);
						}

						if (bForceThrow)
						{
							throw;
						}
					}
					else
					{
						if (iDelay > 0)
						{
							Thread.Sleep(iDelay);
						}

						sRootScheduler.Schedule(this);
					}
				}
			}
		}

		public override IExecutionPolicy Clone(SchedulerDelegate sdSchedulerProcess, ExceptionHandlerDelegate ehdExceptionHandlerDelegate)
		{
			RescheduleOnExceptionExecutionPolicy depNewPolicy = new RescheduleOnExceptionExecutionPolicy(sRootScheduler, sdSchedulerProcess, ehdExceptionHandlerDelegate, iRetries, iDelay, bForceThrow);

			return depNewPolicy;
		}
	}
}
